package purchase.service.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;

import purchase.domain.Purchase;
import purchase.service.PurchaseService;
import purchase.util.PurchaseConstants;

public class PurchaseServiceImpl implements PurchaseService {
	
	private Log log = LogFactory.getLog(PurchaseServiceImpl.class);
	
	private String PurchaseProcessDefinitionName = "purchase";
	
	private JbpmContext jbpmContext;
	
	public PurchaseServiceImpl(JbpmContext jbpmContext) {
		this.jbpmContext = jbpmContext;
	}
	
	public Long getNewOid() {
		String selectNewOidSql = "select test_purchase_seq.nextval from dual";
		
		Long newOid = null;
		Connection connection = jbpmContext.getConnection();
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			statement = connection.createStatement();
			resultSet = statement.executeQuery(selectNewOidSql);
			if (resultSet.next()) {
				newOid = resultSet.getLong(1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				resultSet.close();
				statement.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return newOid;
	}

	public Purchase addPurchase(Purchase purchase) {
		
		String insertSql = "insert into test_purchase(id,title,remark) values(?,?,?)";
		
		Long newOid = getNewOid();
		Connection connection = jbpmContext.getConnection();
		PreparedStatement pstmt = null;
		try {
			connection.setAutoCommit(false);
			
			pstmt = connection.prepareStatement(insertSql);
			pstmt.setLong(1, newOid);
			pstmt.setString(2, purchase.getTitle());
			pstmt.setString(3, purchase.getRemark());
			
			pstmt.executeUpdate();
			
			connection.commit();
		} catch (Exception e) {
			e.printStackTrace();
			try {
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		purchase.setId(newOid);
		
		return purchase;
	}

	public Purchase deletePurchaseById(Long purchaseId) {
		// TODO Auto-generated method stub
		return null;
	}

	public Purchase findPurchaseById(Long purchaseId) {
		
		String selectSql = "select * from test_purchase t10 where t10.id = ? ";
		
		Connection connection = jbpmContext.getConnection();
		PreparedStatement pstmt = null;
		ResultSet resultSet = null;
		Purchase purchase = null;
		try {
			pstmt = connection.prepareStatement(selectSql);
			pstmt.setLong(1, purchaseId);
			resultSet = pstmt.executeQuery();
			
			if (resultSet.next()) {
				purchase = new Purchase();
				purchase.setId(purchaseId);
				purchase.setTitle(resultSet.getString("title"));
				purchase.setRemark(resultSet.getString("remark"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				resultSet.close();
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return purchase;
	}

	public List<Purchase> queryPurchaseList() {
		// TODO Auto-generated method stub
		return null;
	}

	public Purchase updatePurchase(Purchase purchase) {
		String updateSql = "update test_purchase t30 set t30.title = ?, t30.remark = ? where t30.id = ? ";
		
		Connection connection = jbpmContext.getConnection();
		PreparedStatement pstmt = null;
		try {
			connection.setAutoCommit(false);
			
			pstmt = connection.prepareStatement(updateSql);
			pstmt.setString(1, purchase.getTitle());
			pstmt.setString(2, purchase.getRemark());
			pstmt.setLong(3, purchase.getId());
			pstmt.executeUpdate();
			
			connection.commit();
		} catch (Exception e) {
			e.printStackTrace();
			try {
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		Purchase _purchase = findPurchaseById(purchase.getId());
		
		return _purchase;
	}

	public Purchase cancelPurchaseAndProcess(Purchase purchase) {
		
		TaskInstance taskInstance =
			jbpmContext.getTaskInstance(purchase.getTaskBean().getTaskInstanceId());
		
		taskInstance.end();
		
		return purchase;
	}

	public Purchase createPurchaseAndStartProcess(Purchase purchase) {
		Purchase _purchase = addPurchase(purchase);
		
		ProcessDefinition processDefinition = 
			jbpmContext.getGraphSession().findLatestProcessDefinition(this.PurchaseProcessDefinitionName);
		
		ProcessInstance processInstance = processDefinition.createProcessInstance();
		TaskInstance taskInstance = processInstance.getTaskMgmtInstance().createStartTaskInstance();
		taskInstance.setVariable("purchaseId", _purchase.getId());
		taskInstance.setVariable("issueperson", purchase.getTaskBean().getProcessInstanceCreater());
		taskInstance.setVariable("manager", purchase.getTaskBean().getManager());
		
		taskInstance.end();
		
		log.info("create a purchase and create a processInstance.|"+
				"purchaseId:"+_purchase.getId()+"|"+
				"processInstanceId:"+processInstance.getId()+"|");
		
		return _purchase;
	}

	public Purchase findPurchaseAndProcessById(Long purchaseId,Long taskId) {
		
		Purchase _purchase = findPurchaseById(purchaseId);
		
		TaskInstance taskInstance = jbpmContext.getTaskInstance(taskId);
		Token token = taskInstance.getToken();
		String nodeName = taskInstance.getToken().getNode().getName();
		_purchase.getTaskBean().setCurrentProcessStatus(nodeName);
		_purchase.getTaskBean().setTaskInstanceId(taskId);
		_purchase.getTaskBean().setProcessInstanceCreater(
				(String)taskInstance.getVariable("issueperson"));
		_purchase.getTaskBean().setTokenId(token.getId());
		_purchase.getTaskBean().setProcessInstanceId(token.getProcessInstance().getId());
		
		return _purchase;
	}

	public List<Purchase> getMyTaskList(String actorId) {
		
		List<Purchase> purchaseList = new ArrayList<Purchase>();
		List<TaskInstance> taskInstanceList = jbpmContext.getTaskList(actorId);
		
		for (Iterator ite = taskInstanceList.iterator(); ite.hasNext();) {
			TaskInstance taskInstance = (TaskInstance)ite.next();
			Long purchaseId = (Long)taskInstance.getVariable("purchaseId");
			Long taskId = taskInstance.getId();
			
			Purchase purchase = findPurchaseAndProcessById(purchaseId, taskId);
			purchaseList.add(purchase);
		}
		
		return purchaseList;
	}

	public Purchase mgrApprovePurchaseAndProcess(Purchase purchase) {
		//get manager's taskInstance
		TaskInstance taskInstance =
			jbpmContext.getTaskInstance(purchase.getTaskBean().getTaskInstanceId());
		
		String mangerAdvice = purchase.getTaskBean().getManagerAdvice();
		
		//set manager's advice
		taskInstance.setVariable(PurchaseConstants.MANAGER_APPROVE_RESULT, mangerAdvice);
		
		taskInstance.end();
		
		log.info("manager finished approving taskInstance.");
		
		return purchase;
	}

	public Purchase modifyPurchaseAndProcess(Purchase purchase) {
		
		//get my taskInstance
		TaskInstance taskInstance =
			jbpmContext.getTaskInstance(purchase.getTaskBean().getTaskInstanceId());
		
		Purchase _purchase = updatePurchase(purchase);
		
		taskInstance.setVariable(PurchaseConstants.MANAGER_APPROVE_RESULT, "");
		taskInstance.end();
		
		return _purchase;
	}
}
